#include "fxcc/core/graph/common/ModelLoader.h"

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::MeshJack>> ModelLoader::m_MeshJacks;

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::MeshJack>> ModelLoader::m_SkinnedMeshJacks;

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::Animation>> ModelLoader::m_Animations;

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::MaterialView>> ModelLoader::m_Materials;

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::Bones>> ModelLoader::m_Boness;

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::common::MaterialData>> ModelLoader::m_MaterialNativeDatas;

bool ModelLoader::LoadFile(const fxcc::File& file)
{
	std::string fileStr = file.m_RelativePath;

	switch (file.m_FileType)
	{
	case fxcc::_Skinned_:
		return LoadSkinnedFile(fileStr).get();
	case fxcc::_Mesh_:
		return LoadMeshFile(fileStr).get();
	case fxcc::_Anim_:
		return LoadAnimation(fileStr).get();
	case fxcc::_Bone_:
		return LoadBones(fileStr).get();
	case fxcc::_Mat_:
		return LoadMaterialNativeData(fileStr).get();
	case fxcc::_RealMat_:
		return LoadMaterial(fileStr).get();
	default:
		return false;
	}

}

std::shared_ptr<fxcc::graph::common::MeshJack> ModelLoader::LoadMeshFile(const std::string& file)
{
	auto it = m_MeshJacks.find(file);
	if (it != m_MeshJacks.end())
	{
		return it->second;
	}

	fxcc::graph::common::GeometryData geoData;

	if (geoData.ReadFromFile(file))
	{
		m_MeshJacks[file] = fxcc::graph::common::GraphImpl::CreateFixedMesh(geoData);
		return m_MeshJacks[file];

	}
	return 0;
}

std::shared_ptr<fxcc::graph::common::MeshJack> ModelLoader::LoadSkinnedFile(const std::string& file)
{
	auto it = m_SkinnedMeshJacks.find(file);
	if (it != m_SkinnedMeshJacks.end())
	{
		return it->second;
	}


	fxcc::graph::common::SkinnedMeshData skinnedMeshData;
	fxcc::graph::common::GeometryData geoData;
	
	std::string filename = fs::path(file).filename().string();
	std::string fileNameNoSuffix = fxcc::Base::GetNoSuffixName(filename);
	std::string _dir = fxcc::FileUtil::GetParentDir(file);

	std::string geoDataPath = (fs::path(_dir) / (fileNameNoSuffix + ".mesh")).string();

	if (skinnedMeshData.ReadFromFile(file) && geoData.ReadFromFile(geoDataPath))
	{
		m_SkinnedMeshJacks[file] = fxcc::graph::common::GraphImpl::CreateSkinnedMesh(geoData, skinnedMeshData);
		return m_SkinnedMeshJacks[file];

	}
	return 0;

}

std::shared_ptr<fxcc::graph::common::Animation> ModelLoader::LoadAnimation(const std::string& file)
{
	//auto it = m_Animations.find(file);
	//if (it != m_Animations.end())
	//{
	//	return it->second;
	//}

	auto inst = std::make_shared<fxcc::graph::common::Animation>();
	fxcc::yml::Serializer serialzer;;
	bool flag = serialzer.DecodePath<fxcc::graph::common::Animation>(file, *inst);

	return inst;
}

std::shared_ptr<fxcc::graph::common::Bones> ModelLoader::LoadBones(const std::string& file)
{
	auto inst = std::make_shared<fxcc::graph::common::Bones>();
	fxcc::yml::Serializer serialzer;;
	bool flag = serialzer.DecodePath<fxcc::graph::common::Bones>(file, *inst);

	return inst;
}

std::shared_ptr<fxcc::graph::common::MaterialView> ModelLoader::LoadMaterial(const std::string& file)
{
	auto it = m_Materials.find(file);
	if (it != m_Materials.end())
	{
		return it->second;
	}

	auto inst = std::make_shared<fxcc::graph::common::MaterialView>();
	fxcc::yml::Serializer serialzer;;
	bool flag = serialzer.DecodePath<fxcc::graph::common::MaterialView>(file, *inst);

	if (flag) {
		m_Materials[file] = inst;
		return m_Materials[file];
	}
	return 0;
}

std::shared_ptr<fxcc::graph::common::MaterialData> ModelLoader::LoadMaterialNativeData(const std::string& file)
{
	auto it = m_MaterialNativeDatas.find(file);
	if (it != m_MaterialNativeDatas.end())
	{
		return it->second;
	}

	auto inst = std::make_shared<fxcc::graph::common::MaterialData>();
	fxcc::yml::Serializer serialzer;;
	bool flag = serialzer.DecodePath<fxcc::graph::common::MaterialData>(file, *inst);

	if (flag) {
		m_MaterialNativeDatas[file] = inst;
		return m_MaterialNativeDatas[file];
	}
	return 0;
}

